home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / mail / YAM22src.lha / YAM_MI.c < prev    next >
C/C++ Source or Header  |  2000-11-03  |  15KB  |  522 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 2000  Marcel Beck <mbeck@yam.ch>
  5.  
  6.  This program is free software; you can redistribute it and/or modify
  7.  it under the terms of the GNU General Public License as published by
  8.  the Free Software Foundation; either version 2 of the License, or
  9.  (at your option) any later version.
  10.  
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  
  16.  You should have received a copy of the GNU General Public License
  17.  along with this program; if not, write to the Free Software
  18.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20.  YAM Official Support Site :  http://www.yam.ch
  21.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  22.  
  23. ***************************************************************************/
  24.  
  25. #include "YAM.h"
  26.  
  27. /***************************************************************************
  28.  MIME I/O routines
  29. ***************************************************************************/
  30.  
  31. /// Global variables
  32. static char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  33. static char basis_hex[] = "0123456789ABCDEF";
  34.  
  35. static char index_64[128] = {
  36.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  37.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  38.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
  39.    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
  40.    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
  41.    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
  42.    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
  43.    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
  44. };
  45. static char index_hex[128] = {
  46.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  47.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  48.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  49.     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
  50.    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  51.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  52.    -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
  53.    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
  54. };
  55.  
  56. #define hexchar(c)  (((c) > 127) ? -1 : index_hex[(c)])
  57. #define char64(c)  (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
  58. #define SUMSIZE 64
  59. #define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
  60.  
  61. static BOOL InNewline = FALSE;
  62. static BOOL CRpending = FALSE;
  63. BOOL *NeedsPortableNewlines;
  64. ///
  65.  
  66. /// nextcharin
  67. //  Reads next byte from a text files, handles CRLF line breaks
  68. int nextcharin(FILE *infile, BOOL PortableNewlines)
  69. {
  70.    int c;
  71.  
  72.    if (!PortableNewlines) return fgetc(infile);
  73.    if (InNewline) { InNewline = FALSE; return 10; }    /***BUG***/
  74.    c = fgetc(infile);
  75.    if (c == '\n') { InNewline = TRUE; return 13; }
  76.    return c;
  77. }
  78. ///
  79. /// output64chunk
  80. //  Writes three bytes in base64 format
  81. void output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
  82. {
  83.    fputc(basis_64[c1>>2], outfile);
  84.    fputc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
  85.    if (pads == 2) 
  86.    {
  87.       fputs("==", outfile);
  88.    } 
  89.    else if (pads) 
  90.    {
  91.       fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  92.       fputc('=', outfile);
  93.    }
  94.    else 
  95.    {
  96.       fputc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
  97.       fputc(basis_64[c3 & 0x3F], outfile);
  98.    }
  99. }
  100. ///
  101. /// to64
  102. //  Encodes a file using base64 format
  103. void to64(FILE *infile, FILE *outfile, BOOL PortableNewlines)
  104. {
  105.    int c1, c2, c3, ct=0;
  106.    InNewline = 0;
  107.    while ((c1 = nextcharin(infile, PortableNewlines)) != -1)
  108.    {
  109.       c2 = nextcharin(infile, PortableNewlines);
  110.       if (c2 == -1)
  111.          output64chunk(c1, 0, 0, 2, outfile);
  112.       else
  113.       {
  114.          c3 = nextcharin(infile, PortableNewlines);
  115.          if (c3 == -1) output64chunk(c1, c2, 0, 1, outfile);
  116.          else          output64chunk(c1, c2, c3, 0, outfile);
  117.       }
  118.       ct += 4;
  119.       if (ct > 71) { fputc('\n', outfile); ct = 0; }
  120.    }
  121.    if (ct) fputc('\n', outfile);
  122. }
  123. ///
  124. /// almostputc
  125. //  Writes a bytes, handles line breaks and translation tables
  126. void almostputc(int c, FILE *outfile, struct TranslationTable *tt, BOOL PortableNewlines)
  127. {
  128.    if (tt) c = (int)tt->Table[(UBYTE)c];
  129.    if (CRpending) 
  130.    {
  131.       if (c == 10) { fputc('\n', outfile); CRpending = FALSE; }
  132.       else
  133.       {
  134.          fputc(13, outfile);
  135.          if (c != 13) { fputc(c, outfile); CRpending = FALSE; }
  136.       }
  137.    } 
  138.    else 
  139.       if (PortableNewlines && c == 13) CRpending = TRUE; else fputc(c, outfile);
  140. }
  141. ///
  142. /// from64txt
  143. //  Decodes a string in base64 format
  144. void from64txt(char *src, char *dst, struct TranslationTable *tt)
  145. {
  146.    int c1, c2, c3, c4;
  147.    UBYTE c;
  148.  
  149.    while (c1 = (int)*src++)
  150.    {
  151.       if (ISpace((char)c1)) continue;
  152.       do { c2 = (int)*src++; } while (c2 && ISpace((char)c2));
  153.       do { c3 = (int)*src++; } while (c3 && ISpace((char)c3));
  154.       do { c4 = (int)*src++; } while (c4 && ISpace((char)c4));
  155.       if (!c2 || !c3 || !c4) return;
  156.       c1 = char64(c1); c2 = char64(c2); c = (UBYTE)((c1<<2) | ((c2&0x30)>>4));
  157.       *dst++ = tt ? (char)tt->Table[c] : (char)c;
  158.       if (c3 != '=') 
  159.       {
  160.          c3 = char64(c3); c = (UBYTE)(((c2&0XF) << 4) | ((c3&0x3C) >> 2));
  161.          *dst++ = tt ? (char)tt->Table[c] : (char)c;
  162.          if (c4 != '=') 
  163.          {
  164.             c4 = char64(c4); c = (UBYTE)(((c3&0x03) <<6) | c4);
  165.             *dst++ = tt ? (char)tt->Table[c] : (char)c;
  166.          }
  167.       }
  168.    }
  169. }
  170. ///
  171. /// from64
  172. //  Decodes a file in base64 format
  173. void from64(FILE *infile, FILE *outfile, struct TranslationTable *tt, BOOL PortableNewlines)
  174. {
  175.    int c1, c2, c3, c4;
  176.    BOOL DataDone = FALSE;
  177.  
  178.    CRpending = FALSE;
  179.    while ((c1 = fgetc(infile)) != -1) 
  180.    {
  181.       if (ISpace((char)c1)) continue;
  182.       if (DataDone) continue;
  183.       do { c2 = fgetc(infile); } while (c2 != -1 && ISpace((char)c2));
  184.       do { c3 = fgetc(infile); } while (c3 != -1 && ISpace((char)c3));
  185.       do { c4 = fgetc(infile); } while (c4 != -1 && ISpace((char)c4));
  186.       if (c2 == -1 || c3 == -1 || c4 == -1) 
  187.       {
  188.          ER_NewError(GetStr(MSG_ER_UnexpEOFB64), NULL, NULL);
  189.          return;
  190.       }
  191.       if (c1 == '=' || c2 == '=') { DataDone = TRUE; continue; }
  192.       c1 = char64(c1);
  193.       c2 = char64(c2);
  194.       almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, tt, PortableNewlines);
  195.       if (c3 == '=') 
  196.          DataDone = TRUE;
  197.       else 
  198.       {
  199.          c3 = char64(c3);
  200.          almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, tt, PortableNewlines);
  201.          if (c4 == '=') 
  202.             DataDone = 1;
  203.          else  
  204.          {
  205.             c4 = char64(c4);
  206.             almostputc((((c3&0x03) <<6) | c4), outfile, tt, PortableNewlines);
  207.          }
  208.       }
  209.    }
  210.    if (CRpending) fputc(13, outfile);
  211. }
  212. ///
  213. /// toqp
  214. //  Encodes a file using quoted-printable format
  215. void toqp(FILE *infile, FILE *outfile)
  216. {
  217.    int c, ct = 0, prevc = 255;
  218.  
  219.    while ((c = fgetc(infile)) != -1)
  220.    {
  221.       if ((c < 32 && (c != '\n' && c != '\t')) || (c == '=') || (c >= 127) || (ct == 0 && c == '.')) 
  222.       {
  223.          fputc('=', outfile);
  224.          fputc(basis_hex[c>>4], outfile);
  225.          fputc(basis_hex[c&0xF], outfile);
  226.          ct += 3;
  227.          prevc = 'A';
  228.       }
  229.       else if (c == '\n') 
  230.       {
  231.          if (prevc == ' ' || prevc == '\t') 
  232.          {
  233.             fputs("=\n", outfile);
  234.          }
  235.          fputc('\n', outfile);
  236.          ct = 0;
  237.          prevc = c;
  238.       } 
  239.       else 
  240.       {
  241.          if (c == 'F' && prevc == '\n') 
  242.          {
  243.             if ((c = fgetc(infile)) == 'r') 
  244.                if ((c = fgetc(infile)) == 'o') 
  245.                   if ((c = fgetc(infile)) == 'm') 
  246.                      if ((c = fgetc(infile)) == ' ') { fputs("=46rom", outfile);  ct += 6; }
  247.                      else { fputs("From", outfile); ct += 4; }
  248.                   else { fputs("Fro", outfile); ct += 3; }
  249.                else { fputs("Fr", outfile); ct += 2; }
  250.             else { fputc('F', outfile); ++ct; }
  251.             ungetc(c, infile);
  252.             prevc = 'x'; 
  253.          } 
  254.          else
  255.          {
  256.             fputc(c, outfile);
  257.             ++ct;
  258.             prevc = c;
  259.          }
  260.       }
  261.       if (ct > 72) 
  262.       {
  263.          fputs("=\n", outfile);
  264.          ct = 0;
  265.          prevc = '\n';
  266.       }
  267.    }
  268.    if (ct) fputs("=\n", outfile);
  269. }
  270. ///
  271. /// fromform
  272. //  Converts an url-encoded file into plain text
  273. void fromform(FILE *infile, FILE *outfile, struct TranslationTable *tt)
  274. {
  275.    unsigned int c;
  276.    while ((c = fgetc(infile)) != -1)
  277.    {
  278.       switch (c)
  279.       {
  280.          case '&': fputc('\n', outfile); break;
  281.          case '%': c = (index_hex[fgetc(infile)]<<4)+index_hex[fgetc(infile)];
  282.                    switch (c)
  283.                    {
  284.                       case '\n': fputs("\n ", outfile); break;
  285.                       case '\r': break;
  286.                       default  : fputc(tt ? (int)tt->Table[(UBYTE)c] : c, outfile); break;
  287.                    }
  288.                    break;
  289.          case '+': fputc(' ', outfile); break;
  290.          case '=': fputs(" = ", outfile); break;
  291.          default : fputc(tt ? (int)tt->Table[(UBYTE)c] : c, outfile); break;
  292.       }
  293.    }
  294. }
  295. ///
  296. /// fromqptxt
  297. //  Decodes a string in quoted-printable format
  298. void fromqptxt(char *src, char *dst, struct TranslationTable *tt)
  299. {
  300.    unsigned int c1, c2;
  301.    UBYTE c;
  302.  
  303.    while (c1 = *src++) 
  304.       if (c1 == '=') 
  305.       {
  306.          c1 = *src++; c2 = *src++;
  307.          c1 = hexchar(c1); c2 = hexchar(c2); c = (UBYTE)(c1<<4 | c2);
  308.          *dst++ = tt ? (char)tt->Table[c] : (char)c;
  309.       }
  310.       else *dst++ = tt ? (char)tt->Table[(UBYTE)c1] : (char)c1;
  311. }
  312. ///
  313. /// fromqp
  314. //  Decodes a file in quoted-printable format
  315. void fromqp(FILE *infile, FILE *outfile, struct TranslationTable *tt)
  316. {
  317.    unsigned int c1, c2;
  318.    BOOL neednewline = FALSE;
  319.  
  320.    while ((c1 = fgetc(infile)) != -1) 
  321.    {
  322.       if (neednewline) { fputc('\n', outfile); neednewline = FALSE; };
  323.       if (c1 == '=')
  324.       {
  325.          c1 = fgetc(infile);
  326.          if (c1 != '\n')
  327.          {
  328.             c2 = fgetc(infile);
  329.             c1 = hexchar(c1);
  330.             c2 = hexchar(c2);
  331.             fputc(tt ? (int)tt->Table[(UBYTE)(c1<<4 | c2)] : c1<<4 | c2, outfile);
  332.          }
  333.       }
  334.       else if (c1 == '\n') neednewline = TRUE;
  335.       else fputc(tt ? (int)tt->Table[(UBYTE)c1] : c1, outfile);
  336.    }
  337.    if (neednewline) fputc('\n', outfile);
  338. }
  339. ///
  340. /// DoesNeedPortableNewlines
  341. //  Checks if line breaks must be portable (CRLF)
  342. BOOL DoesNeedPortableNewlines(char *ctype)
  343. {
  344.    if (!strnicmp(ctype, "text", 4)) return TRUE;
  345.    if (!strnicmp(ctype, "message", 7)) return TRUE;
  346.    if (!strnicmp(ctype, "multipart", 9)) return TRUE;
  347.    return FALSE;
  348. }
  349. ///
  350.  
  351. /*** UU encode/decode stuff ***/
  352. /// uueget
  353. //  Decodes four UU encoded bytes
  354. void uueget(char *ptr, FILE *outfp, int n)
  355. {
  356.    int c1, c2, c3;
  357.    unsigned char p0, p1, p2, p3;
  358.  
  359.    p0 = (ptr[0] - ' ') & 0x3F;
  360.    p1 = (ptr[1] - ' ') & 0x3F;
  361.    p2 = (ptr[2] - ' ') & 0x3F;
  362.    p3 = (ptr[3] - ' ') & 0x3F;
  363.    c1 = p0 << 2 | p1 >> 4;
  364.    c2 = p1 << 4 | p2 >> 2;
  365.    c3 = p2 << 6 | p3;
  366.    if (n >= 1) fputc(c1, outfp);
  367.    if (n >= 2) fputc(c2, outfp);
  368.    if (n >= 3) fputc(c3, outfp);
  369. }
  370. ///
  371. /// gettxtline
  372. //  Reads next line of UU encoded string
  373. BOOL gettxtline(char *buf, int size, char **rptr)
  374. {
  375.    int c;
  376.    char *ptr = buf;
  377.  
  378.    for (c = 0; c < size; ++c)buf[c] = ' ';
  379.    do 
  380.    {
  381.       c = (int)**rptr; (*rptr)++;
  382.       if (!c) { *ptr = '\0'; return (BOOL)(ptr == buf); }
  383.       else if (c == '\n' || c == '\r') { *ptr = '\0'; return False; }
  384.       else if (ptr == buf && c == '>') continue;
  385.       else if (size > 0) { *ptr++ = c; size--; }
  386.    } while (TRUE);
  387.    return False;
  388. }
  389. ///
  390. /// fromuuetxt
  391. //  Decodes a string in UUE format
  392. void fromuuetxt(char **txt, FILE *outfp)
  393. {
  394.    char buf[SIZE_LINE];
  395.  
  396.    while (TRUE)
  397.    {
  398.       if (gettxtline(buf, sizeof(buf), txt)) 
  399.       {
  400.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  401.          return;
  402.       }        
  403.       if (!strncmp(buf, "begin", 5)) break;
  404.    }  
  405.    while (TRUE) 
  406.    {
  407.       if (gettxtline(buf, sizeof(buf), txt)) 
  408.       {
  409.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  410.          return;
  411.       }        
  412.       else if (!strncmp(buf, "end", 5)) break;
  413.       else if (*buf == '\0') continue;
  414.       else 
  415.       {
  416.          int length = (*buf - ' ');
  417.          if (*buf == '`') length = 0;
  418.          if (length < 0 || length > 63) 
  419.             ER_NewError(GetStr(MSG_ER_InvalidLength), (char *)length, NULL);
  420.          else 
  421.          {
  422.             char *ptr = buf + 1;
  423.             while (length > 0) { uueget(ptr, outfp, length); length -= 3; ptr += 4; }
  424.          }
  425.       }
  426.    }
  427. }
  428. ///
  429. /// getline
  430. //  Reads next line from a UU encoded file
  431. BOOL getline(char *buf, int size, FILE *fp)
  432. {
  433.    int c;
  434.    char *ptr = buf;
  435.  
  436.    for (c = 0; c < size; ++c)buf[c] = ' ';
  437.    do 
  438.    {
  439.       if ((c = fgetc(fp)) == -1) {*ptr = '\0'; return (BOOL)(ptr == buf); }
  440.       else if (c == '\n' || c == '\r') { *ptr = '\0'; return False; }
  441.       else if (ptr == buf && c == '>') continue;
  442.       else if (size > 0) { *ptr++ = c; size--; }
  443.    } while (TRUE);
  444.    return False;
  445. }
  446. ///
  447. /// fromuue
  448. //  Decodes a file in UUE format
  449. void fromuue(FILE *infp, FILE *outfp)
  450. {
  451.    char buf[SIZE_LINE];
  452.  
  453.    while (TRUE) 
  454.    {
  455.       if (getline(buf, sizeof(buf), infp)) 
  456.       {
  457.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  458.          return;
  459.       }        
  460.       if (!strncmp(buf, "begin", 5)) break;
  461.    }  
  462.    while (TRUE) 
  463.    {
  464.       if (getline(buf, sizeof(buf), infp)) 
  465.       {
  466.          ER_NewError(GetStr(MSG_ER_UnexpEOFUU), NULL, NULL);
  467.          return;
  468.       }        
  469.       else if (!strncmp(buf, "end", 5)) break;
  470.       else if (*buf == '\0') continue;
  471.       else 
  472.       {
  473.          int length = (*buf - ' ');
  474.          if (*buf == '`') length = 0;
  475.          if (length < 0 || length > 63) 
  476.             ER_NewError(GetStr(MSG_ER_InvalidLength), (char *)length, NULL);
  477.          else 
  478.          {
  479.             char *ptr = buf + 1;
  480.             while (length > 0) { uueget(ptr, outfp, length); length -= 3; ptr += 4; }
  481.          }
  482.       }
  483.    }
  484. }
  485. ///
  486. /// outdec
  487. //  Encodes three bytes using UUE format
  488. int outdec(char *p, FILE *out)
  489. {
  490.    int c1,c2,c3,c4;
  491.  
  492.    c1 = *p >> 2;
  493.    c2 = (*p << 4) & 060 | (p[1] >> 4) & 017;
  494.    c3 = (p[1] << 2) & 074 | (p[2] >> 6) & 03;
  495.    c4 = p[2] & 077;
  496.    fputc(ENC(c1), out);
  497.    fputc(ENC(c2), out);
  498.    fputc(ENC(c3), out);
  499.    fputc(ENC(c4), out);
  500.    return (p[0]+p[1]+p[2]) % SUMSIZE;
  501. }
  502. ///
  503. /// touue
  504. //  Encodes a file using UUE format
  505. void touue(FILE *in, FILE *out)
  506. {
  507.    char buf[80];
  508.    int i,n,checksum;
  509.  
  510.    for (;;) 
  511.    {
  512.       n = fread(buf, 1, 45, in);
  513.       fputc(ENC(n), out);
  514.       checksum = 0;
  515.       for (i = 0; i < n; i += 3) checksum = (checksum+outdec(&buf[i], out))%SUMSIZE;
  516.       fputc(ENC(checksum), out);
  517.       fputc('\n', out);
  518.       if (n <= 0) break;
  519.    }
  520. }
  521. ///
  522.